#include "C_Camera.h"

C_Camera::C_Camera()
{
	Default();
}

C_Camera::C_Camera(const float3 & eye, 
									 const float3 & dir, 
									 const float3 & up, 
									 float fov, float asp, 
									 float zn, float zf)
{
	this->eye = eye;
	this->dir = normalize(dir);
	this->up  = up;
	this->at  = eye + this->dir;

	this->fov = fov;
	this->asp = asp;
	this->zn  = zn;
	this->zf  = zf;

	DUR();
}

void	C_Camera::Default()
{
	eye = f3();
	dir = f3(0, 0, 1);
	up = f3(0, 1, 0);

	at = eye + dir;

	fov = 60.0f;
	asp = 1.0f;
	zn  = 0.1f;
	zf  = 100.0f;
}

float3	C_Camera::Right() { return normalize(cross(dir, up)); }

float	C_Camera::zF(float zf)
{
	this->zf = zf;
	return zf;
}

float	C_Camera::zN(float zn)
{
	this->zn = zn;
	return zn;
}

float	C_Camera::Asp(float asp)
{
	this->asp = asp;
	return asp;
}

float	C_Camera::FoV(float fov_angle)
{
	this->fov = fov_angle;
	return fov_angle;
}

float3	C_Camera::Up(float3 up)
{
	this->up = normalize(up);

	DUR();

	return this->up;
}

float3	C_Camera::Up(float x, float y, float z) 
{
	set(up, x, y, z);
	up = normalize(up);

	DUR();

	return up;
}

float3	C_Camera::At(float3 at)
{
	this->at = at;
	dir = normalize(at - eye);

	DUR();

	return this->at;
}

float3	C_Camera::At(float x, float y, float z)
{
	set(at, x, y, z);
	dir = normalize(at - eye);

	DUR();

	return at;
}

float3	C_Camera::Dir(float3 dir)
{
	this->dir = normalize(dir);
	at = eye + this->dir;

	DUR();

	return this->dir;
}

float3	C_Camera::Dir(float x, float y, float z)
{
	set(dir, x, y, z);
	dir = normalize(dir);
	at = eye + dir;

	DUR();

	return dir;
}

float3	C_Camera::Eye(float3 eye)
{
	this->eye = eye;
	at = this->eye + dir;
	return this->eye;
}

float3	C_Camera::Eye(float x, float y, float z)
{
	set(eye, x, y, z);
	at = eye + dir;
	return eye;
}

void	C_Camera::Update(float dx, float dy)
{
	float3 right = Right();

	dir = dir + dx * right + dy * up;

	at = eye + dir;

	DUR();
}

void	C_Camera::Update(uint32 direction, float speed)
{
	float3 right = Right();
	switch (direction)
	{
	case e_StrafeLeft:
		eye -= right * speed;
		break;

	case e_StrafeRight:
		eye += right * speed;
		break;

	case e_StepForward:
		eye += dir * speed;
		break;

	case e_StepBackward:
		eye -= dir * speed;
		break;
	}

	at = eye + dir;
}  

void	C_Camera::DUR()
{
	const float3 upY = {0, 1, 0};
	const float3 upZ = {0, 0, 1};

	float3 u = cross(dir, upY);

	if (length(u) < 0.001)
	{
		u = cross(dir, upZ);
	}

	u = normalize(u);

	up = normalize(cross(u, dir));

}

void	C_Camera::DUR(float3 dir)
{
	Dir(dir);

	DUR();
}

void	C_Camera::DUR(float x, float y, float z)
{
	Dir(x, y, z);

	DUR();
}